textlayout: make GtkTextLineDisplay reference counted
authorChristian Hergert <chergert@redhat.com>
Tue, 23 Jul 2019 21:52:14 +0000 (14:52 -0700)
committerChristian Hergert <chergert@redhat.com>
Tue, 23 Jul 2019 21:52:14 +0000 (14:52 -0700)
This makes GtkTextLineDisplay use GRcBox instead of g_slice_*
directly. By using reference counting for this structure, we
can ensure that we hold an extra ref for one_display_cache as
well as caching additional GtkTextLineDisplay for the visible
range in the future.

gtk/gtktextlayout.c
gtk/gtktextlayoutprivate.h

index 6974353b7c2f89429488d60aa84f853e6dcf32f6..f150c927fa8863e3ec432faed55058ca39d2647d 100644 (file)
@@ -197,12 +197,7 @@ gtk_text_layout_dispose (GObject *object)
   g_clear_object (&layout->ltr_context);
   g_clear_object (&layout->rtl_context);
 
-  if (layout->one_display_cache)
-    {
-      GtkTextLineDisplay *tmp_display = layout->one_display_cache;
-      layout->one_display_cache = NULL;
-      gtk_text_layout_free_line_display (layout, tmp_display);
-    }
+  g_clear_pointer (&layout->one_display_cache, gtk_text_line_display_unref);
 
   if (layout->preedit_attrs != NULL)
     {
@@ -826,20 +821,17 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
 {
   if (layout->one_display_cache && line == layout->one_display_cache->line)
     {
-      GtkTextLineDisplay *display = layout->one_display_cache;
-
       if (cursors_only)
        {
-          if (display->cursors)
-            g_array_free (display->cursors, TRUE);
-         display->cursors = NULL;
+          GtkTextLineDisplay *display = layout->one_display_cache;
+
+          g_clear_pointer (&display->cursors, g_array_unref);
          display->cursors_invalid = TRUE;
          display->has_block_cursor = FALSE;
        }
       else
        {
-         layout->one_display_cache = NULL;
-         gtk_text_layout_free_line_display (layout, display);
+          g_clear_pointer (&layout->one_display_cache, gtk_text_line_display_unref);
        }
     }
 }
@@ -2287,19 +2279,17 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
        {
          if (!size_only)
             update_text_display_cursors (layout, line, layout->one_display_cache);
-         return layout->one_display_cache;
+         return gtk_text_line_display_ref (layout->one_display_cache);
        }
       else
         {
-          GtkTextLineDisplay *tmp_display = layout->one_display_cache;
-          layout->one_display_cache = NULL;
-          gtk_text_layout_free_line_display (layout, tmp_display);
+          g_clear_pointer (&layout->one_display_cache, gtk_text_line_display_unref);
         }
     }
 
   DV (g_print ("creating one line display cache (%s)\n", G_STRLOC));
 
-  display = g_slice_new0 (GtkTextLineDisplay);
+  display = g_rc_box_new0 (GtkTextLineDisplay);
 
   display->size_only = size_only;
   display->line = line;
@@ -2619,7 +2609,9 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   if (tags != NULL)
     g_ptr_array_free (tags, TRUE);
 
-  layout->one_display_cache = display;
+  g_assert (layout->one_display_cache == NULL);
+
+  layout->one_display_cache = gtk_text_line_display_ref (display);
 
   if (saw_widget)
     allocate_child_widgets (layout, display);
@@ -2627,20 +2619,32 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   return display;
 }
 
+static void
+gtk_text_line_display_finalize (GtkTextLineDisplay *display)
+{
+  g_clear_object (&display->layout);
+  g_clear_pointer (&display->cursors, g_array_unref);
+}
+
+GtkTextLineDisplay *
+gtk_text_line_display_ref (GtkTextLineDisplay *display)
+{
+  return g_rc_box_acquire (display);
+}
+
+void
+gtk_text_line_display_unref (GtkTextLineDisplay *display)
+{
+  g_rc_box_release_full (display, (GDestroyNotify)gtk_text_line_display_finalize);
+}
+
+/* For compat until we switch away from this */
 void
 gtk_text_layout_free_line_display (GtkTextLayout      *layout,
                                    GtkTextLineDisplay *display)
 {
-  if (display != layout->one_display_cache)
-    {
-      if (display->layout)
-        g_object_unref (display->layout);
-
-      if (display->cursors)
-        g_array_free (display->cursors, TRUE);
-
-      g_slice_free (GtkTextLineDisplay, display);
-    }
+  if (display != NULL)
+    gtk_text_line_display_unref (display);
 }
 
 /* Functions to convert iter <=> index for the line of a GtkTextLineDisplay
index 7aff2074ff8f15b856f2276f91d8c166ebe50f36..366fbb86c81a0e45615483836425dc5c9cde3d93 100644 (file)
@@ -300,6 +300,8 @@ GtkTextLineDisplay* gtk_text_layout_get_line_display  (GtkTextLayout      *layou
                                                        gboolean            size_only);
 void                gtk_text_layout_free_line_display (GtkTextLayout      *layout,
                                                        GtkTextLineDisplay *display);
+GtkTextLineDisplay *gtk_text_line_display_ref         (GtkTextLineDisplay *display);
+void                gtk_text_line_display_unref       (GtkTextLineDisplay *display);
 
 void gtk_text_layout_get_line_at_y     (GtkTextLayout     *layout,
                                         GtkTextIter       *target_iter,